package br.ufrj.dcc.ad.model;

import br.ufrj.dcc.ad.ADSimProperties;
import br.ufrj.dcc.ad.Simulator;
import br.ufrj.dcc.ad.Util;

public class RouterRED extends Router {

	Double avg = 0.0;
	final Double WQ = 0.03;
	final Long MINTH = 5l;
	final Long MAXTH = 15l;
	final Double MAXP = 1.0/50;
	
	Long count = 0l;
	
	Double emptyTime = 0d;
	Double m = 0d;
	
	public RouterRED(Long bufferSize) {
		super(bufferSize);
	}
	
	@Override
	public boolean packageArrived(Package pack) {
		
		if (getBuffer().size() > 0) {
			avg = (1 - WQ)*avg + WQ*getBuffer().size();
			logger.info("avg: {}",avg);
		} else {
			emptyTime = Simulator.getTime() - emptyTime;
			m = Util.convertMillisToSeconds(emptyTime) / (8d * ADSimProperties.getMSS() / ADSimProperties.getCg());
			avg = Math.pow((1 - WQ), m) * avg;
		}
		
		Double pb = MAXP*(avg - MINTH)/(MAXTH - MINTH);
		Double pa = pb / (1 - count*pb);
		
		if (avg.doubleValue() < MINTH.longValue()) {
			addPackage(pack);
		} else if (avg.doubleValue() > MAXTH.longValue()) {
			count = 0l;
			logger.info("pacote descartado preventivamente");
			return false;
		} else {
			if (Math.random() <= pa) {
				count = 0l;
				logger.info("pacote descartado preventivamente");
				return false;
			} else {
				if (!(getBuffer().size() < getBufferCapacity())) {
					count = 0l;
					logger.info("buffer cheio - pacote descartado");
					return false;
				}
				count++;
				addPackage(pack);
			}
		}
		return true;
	}

	
	@Override
	public void packageServiceFinished(Package pack) {
		super.packageServiceFinished(pack);
		
		if (getBuffer().isEmpty()) {
			emptyTime = Simulator.getTime();
		}
	}
}
